package com.book.manager.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.book.manager.base.result.Result;
import com.book.manager.component.LocalCache;
import com.book.manager.component.RedisOpsUtil;
import com.book.manager.constant.RedisKeyPrefixConst;
import com.book.manager.dto.*;
import com.book.manager.exception.MyRuntimeException;
import com.book.manager.mapper.BookMapper;
import com.book.manager.mapper.BookStockMapper;
import com.book.manager.mapper.RelUserBookMapper;
import com.book.manager.model.Book;
import com.book.manager.model.BookStock;
import com.book.manager.model.RelUserBook;
import com.book.manager.model.User;
import com.book.manager.service.BookService;
import com.book.manager.service.authentication.MyAuthenticationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * @author: yfan-chen
 * @description:
 * @create: 2021-08-31 22:41
 **/
@Service
public class BookServiceImpl extends ServiceImpl<BookMapper, Book> implements BookService {

    @Autowired
    private LocalCache cache;
    @Autowired
    private RedisOpsUtil redisOpsUtil;
    @Autowired
    private RelUserBookMapper relUserBookMapper;
    @Autowired
    private BookStockMapper bookStockMapper;
    @Autowired
    private MyAuthenticationService userService;

    @Override
    public Result<Book> getBookDetailWithBookId(BooKIdReq req) {
        //一级缓存
        Book book = cache.get(RedisKeyPrefixConst.FLASH_PROMOTION_PRODUCT_KEY + req.getBookId());
        if (book == null) {
            // 二级缓存
            book = redisOpsUtil.get(RedisKeyPrefixConst.FLASH_PROMOTION_PRODUCT_KEY + req.getBookId(), Book.class);
            if (book != null) {
                cache.setLocalCache(RedisKeyPrefixConst.FLASH_PROMOTION_PRODUCT_KEY + req.getBookId(), book);
            }
        }
        if (book == null) {
            book = baseMapper.findBookWithId(req.getBookId());
            if (book != null) {
                redisOpsUtil.set(RedisKeyPrefixConst.FLASH_PROMOTION_PRODUCT_KEY + req.getBookId(), book,
                        3600+new Random().nextInt(3600),
                        TimeUnit.SECONDS);
                cache.setLocalCache(RedisKeyPrefixConst.FLASH_PROMOTION_PRODUCT_KEY + req.getBookId(), book);
            }
        }
        if (book != null) {
            int sum = bookStockMapper.sumBookCount(book.getBookId());
            int stockSum = bookStockMapper.sumBookStockCount(book.getBookId());
            book.setAllVolume(sum);
            book.setVolume(stockSum);
        }
        return Result.success(book);
    }

    @Override
    public Result<IPage<Book>> listBookWithPageKeyMsg(PageReq pageReq) {
        IPage<Book> bookPage = baseMapper.listBookWithPageKeyMsg(new Page(pageReq.getPage(), pageReq.getPageSize()),
                null);
        if (bookPage != null && bookPage.getRecords() != null) {
            for (Book book : bookPage.getRecords()) {
                int sum = bookStockMapper.sumBookCount(book.getBookId());
                int stockSum = bookStockMapper.sumBookStockCount(book.getBookId());
                book.setAllVolume(sum);
                book.setVolume(stockSum);
            }
        }
        return Result.success(bookPage);
    }

    @Override
    public Result<BorrowBookResp> borrowBookList(BorrowBookReq req) {
        User loginUser = userService.getLoginUser();
        BorrowBookResp resp = new BorrowBookResp();
        for (String bookCode : req.getBookCodeList()) {
            BookStock bookStock = bookStockMapper.findBookStockWithBookCode(bookCode);
            if (bookStock != null && bookStock.getStockStatus() == 1) {
                // 借出
                BorrowBookResp.PurchaseSuccess purchaseSuccess = new BorrowBookResp.PurchaseSuccess();
                purchaseSuccess.setBookId(bookStock.getBookId());
                purchaseSuccess.setBookCode(bookStock.getBookCode());
                if (resp.getPurchaseSuccessList() == null) {
                    resp.setPurchaseSuccessList(new ArrayList<>());
                }
                resp.getPurchaseSuccessList().add(purchaseSuccess);
                recordBorrowRelUserBook(loginUser.getUserId(), bookStock.getBookId(), bookCode);

                bookStock.setStockStatus(0);    // 借出标志
                bookStockMapper.updateById(bookStock);
            } else {
                // 无法出借
                if (resp.getPurchaseFailList() == null) {
                    resp.setPurchaseFailList(new ArrayList<>());
                }
                resp.getPurchaseFailList().add(new BorrowBookResp.PurchaseFail(bookCode));
            }
        }
        return Result.success(resp);
    }

    @Override
    public Result<BorrowBookResp> backBookList(BorrowBookReq req) {
        User loginUser = userService.getLoginUser();
        BorrowBookResp resp = new BorrowBookResp();
        for (String bookCode : req.getBookCodeList()) {
            BookStock bookStock = bookStockMapper.findBookStockWithBookCode(bookCode);
            if (bookStock != null && bookStock.getStockStatus() == 0) {
                // 可以还书
                BorrowBookResp.PurchaseSuccess purchaseSuccess = new BorrowBookResp.PurchaseSuccess();
                purchaseSuccess.setBookId(bookStock.getBookId());
                purchaseSuccess.setBookCode(bookStock.getBookCode());
                if (resp.getPurchaseSuccessList() == null) {
                    resp.setPurchaseSuccessList(new ArrayList<>());
                }
                resp.getPurchaseSuccessList().add(purchaseSuccess);
                recordBackRelUserBook(loginUser.getUserId(), bookStock.getBookId(), bookCode);

                bookStock.setStockStatus(1);    // 还书标志
                bookStockMapper.updateById(bookStock);
            } else {
                // 无法还书
                if (resp.getPurchaseFailList() == null) {
                    resp.setPurchaseFailList(new ArrayList<>());
                }
                resp.getPurchaseFailList().add(new BorrowBookResp.PurchaseFail(bookCode));
            }
        }
        return Result.success(resp);
    }

    @Override
    public Result<List<BookBorrowDetail>> listBookBorrowDetailWithBookId(BooKIdReq req) {
        List<BookBorrowDetail> bookBorrowDetails = relUserBookMapper.borrowBookDetailWithBookId(req.getBookId());
        return Result.success(bookBorrowDetails);
    }

    @Override
    public Result<List<BookBorrowDetail>> listBookBorrowDetailWithMe() {
        User loginUser = userService.getLoginUser();
        List<BookBorrowDetail> bookBorrowDetails = relUserBookMapper.borrowBookDetailWithMe(loginUser.getUserId());
        return Result.success(bookBorrowDetails);
    }

    private void recordBorrowRelUserBook(Integer userId, Integer bookId, String bookCode) {
        RelUserBook relUserBook = relUserBookMapper.findRelUserBookWithUserIdBookId(userId, bookId, bookCode);
        if (relUserBook != null) {
            throw new MyRuntimeException("借书失败，请联系管理员");
        }
        relUserBook = new RelUserBook();
        relUserBook.setUserId(userId);
        relUserBook.setBookId(bookId);
        relUserBook.setBookCode(bookCode);
        relUserBook.setCreateTime(Calendar.getInstance().getTimeInMillis());
        relUserBook.setUpdateTime(Calendar.getInstance().getTimeInMillis());
        relUserBook.setLoan(Calendar.getInstance().getTimeInMillis());
        relUserBook.setIsValid(1);
        relUserBookMapper.insert(relUserBook);
    }

    private void recordBackRelUserBook(Integer userId, Integer bookId, String bookCode) {
        RelUserBook relUserBook = relUserBookMapper.findRelUserBookWithUserIdBookId(userId, bookId, bookCode);
        if (relUserBook != null) {
            relUserBook.setBack(Calendar.getInstance().getTimeInMillis());
            relUserBook.setUpdateTime(Calendar.getInstance().getTimeInMillis());
            relUserBookMapper.updateById(relUserBook);
            return;
        }
        throw new MyRuntimeException("还书失败，请联系管理员");

    }
}
